//Lindsay Ergenekan 
//ergenekl@onid.oregonstate.edu 
//CS311 - 400
//Homework 5 - Uniqify  


#include "hw5.h"

#define MAXBYTES = 50;


int main(int argc, char *argv[])
{

    char c;
    int n; 
 //   int pfd[2];
    int i; //counter into
    int j;//counter int
   const char delimiter[] = " \n!\"#$%,.?][-+_\\/<>=@^:;&\'-')(*1234567890";
    char s1 [200];
    char * token; //variable to record the tokens
    int count; //variable to record the number of words
    void *root = NULL; //pointer to the root of the bst
    struct word_t *ret = malloc(sizeof(word_t)); //word_t structure - catches the return value of the tsearch to update
    word_t *val; //value
    char * ptr; //pointer to help use the tokens
 //   char * token_array[10000];
    key_t testKey; //variable test key
    struct messsage_struct *message_t = malloc(sizeof(message_struct));
    struct message_struct msg; //variable message send buffer
    int received_bytes; 
    struct message_struct rcv; //variable message receive buffer
    int msgqid; //variable to record the msg qid
//    int * message_array; //variable to hold the message IDs
    struct message_struct parent_child_rcv; //variable message receive buffer
    int parent_counter; 

    while ((c = getopt(argc, argv, "n:")) != -1)
    switch (c){ 
        case 'n':
            n = atoi(argv[2]);
            if (n >= 50){
                printf("Too large a number.");
                exit(1);
            }
   //         else { 
   //          printf("%d \n", n);
    //        }
        }

//create the test key
testKey = ftok(__FILE__, 's');

for (i = 0; i < n; ++i)
{
    message_array[i] = msgget(testKey+i, 0666 | IPC_CREAT); // creates message queue to post and pull from
    printf(" %d Processes:  %d \n", i, message_array[i]);
}


//msgqid = message_array[1];

received_bytes = 0; //set the received variable to 0
//printf ("received bytes at 0 : %d \n", received_bytes);

for (i =0; i < n; ++i)
{ 
  switch (fork()) {

    case -1:
       printf("fork issue \n");
       exit(1);
    case 0:   
    for (;;)
    {
        received_bytes = msgrcv(message_array[i], &rcv, sizeof(rcv.mtext), 0, MSG_NOERROR);  
//        printf(" msgrcv bytes = %d \n", received_bytes); 
//        printf("message type: %d \n", rcv.mtype);

        //   printf ("received bytes after msgrcvd %d \n", received_bytes);
        if(received_bytes == -1)
            {
 //               printf(" EXIT [%d] \n", message_array[i]);
            exit(2);}
        else if (rcv.mtype == 7)
            {
//                printf("exiting\n");
//walk through the tree
            twalk(root, walker);
            message_struct.mtype = 8;  
//////send the type 7 to termination
            received_bytes = msgsnd(message_array[i], &message_struct, sizeof(message_struct.mtext), MSG_NOERROR);
   //         printf(" WALKER sent [%d] type (%d)  (%s) \n", message_array[i], message_struct.mtype, message_struct.mtext);
            exit(1);}
        else
            {
        //  printf(" child [%d] received type %d \n", msgqid, rcv.mtype);
   //         printf(" child [%d] : %s  \n", message_array[i], rcv.mtext);
            val = calloc(1, sizeof(word_t));
            val->word = strdup(rcv.mtext);
 //           val->message_q_no = message_array[i];
            val->message_q_no = i;
  //         printf(" val->word : %s  \n", val->word);            
            ret = tsearch(val, &root, cmp);
        //incriment the number of the item
           (*(word_t **)ret)->number += 1;
            } 
    }
    default:           
        break;
  }
}

count = 0; //set variable to count the number of words to 0
i = 0; //set i to 0
 j=0; //set j to 0
while (fgets(s1, 200, stdin))
{
    ptr = s1;
//this while loop allows individual tokens to be handled
    while ((token =strtok(ptr, delimiter)) != NULL)
        {
///////////////////////////////////THiS IS WHERE I HANDLE INDIVIDUAL TOKENS!!!!!!!!!!!!!
//reset the ptr
        ptr = NULL;

//make all lower case
        for (i =0; i < strlen(token); ++i)
                {token[i] = tolower(token[i]);}
//put the value in the message_struct
        message_struct.mtype = 1;
        strcpy(message_struct.mtext, token);

        received_bytes =0; 

//print what was put into the message_struct
//       printf(" %d %s \n", message_struct.mtype, message_struct.mtext);
        received_bytes = msgsnd(message_array[j%n], &message_struct, sizeof(message_struct.mtext), MSG_NOERROR);
        ++count; 
        ++j; 

       }//
 //   printf("finished fgets while loop");
    }

message_struct.mtype = 7; 
//////send the type 7 to termination
for (i = 0; i < n; ++i)
{
    received_bytes = msgsnd(message_array[i], &message_struct, sizeof(message_struct.mtext), MSG_NOERROR);
}

printf("COUNTER : %d \n", count);
printf("parent counter : %d \n", parent_counter);

/////////////////////////////////////////////////////////////////////////function to receive message back from children
for (;;)
{
 //   for(i =0; i< n; ++i)
 //   {
/////receive twalk messages from children   
//   printf(" %d Processes:  %d \n", i, message_array[i]);
    received_bytes = msgrcv(message_array[i%n], &parent_child_rcv, sizeof(parent_child_rcv.mtext), 0, MSG_NOERROR);  
    printf(" RECEIVED FROM CHILD!!!!! [%d] (%s) \n", parent_child_rcv.mtype, parent_child_rcv.mtext);
//      printf ("Bytes from CHILD %d \n", received_bytes);
//    ++i;
  if(received_bytes == -1)
            {
                printf(" [%d] EXIT [%d] \n", (i%n), message_array[i%n]);
            break;}
        else if (parent_child_rcv.mtype == 8 && parent_counter == count)
            {
  //          printf(" [%d] (%s) \n", parent_child_rcv.mtype, parent_child_rcv.mtext);
 //      printf ("child to parrent bytes %d \n", received_bytes);
            printf("received CHILD end signal \n");
            break;}
        else
            {
     printf(" [%d] RECEIVED FROM CHILD!!!!! [%d] (%s) \n", (i%n), parent_child_rcv.mtype, parent_child_rcv.mtext);
     ++parent_counter;
//      printf(" [%d] RECEIVED FROM CHILD!!!!! [%d] (%s) \n", (i%n), parent_child_rcv.mtype, parent_child_rcv.mtext);
//      printf ("child to parrent bytes %d \n", received_bytes);
        }
    ++i;
//    }
}


for (i = 0; i < n; ++i)
{
    if (wait(NULL) == -1)
        { printf("wait %d did not work\n", i);}
//    else 
//        {printf("wait found child\n");}
}


/////////////////////////////////////////////////////////////////////////Make sure the message arrays are killed
    for (i = 0; i < n; ++i)
    {
        msgctl(message_array[i], IPC_RMID, NULL); // remove the queue
        printf("This message (%d) was killed \n", message_array[i]);

    }

////////////////////////////////////////////////////////////////////Just for practice, check they're killed
    for (i = 0; i < n; ++i)
    {
       kill(message_array[i],SIGTERM);//kill the child process
 //                                                                                                printf("killed child");
    }
return 0; 
}

/////////////////////////////////////Altered from https://code.google.com/p/semicomplete/source/browse/codesamples/tsearch-example.c
int cmp(const void *a, const void *b)
{
    word_t *fa, *fb;
    fa = (word_t*)a;
    fb = (word_t*)b;
return strcmp(fa->word, fb->word);
}


/////////////////////////////////////Altered from https://code.google.com/p/semicomplete/source/browse/codesamples/tsearch-example.c
void walker(const void *node, const VISIT which, const int depth)
{
//                                                                                                  printf("in walker");
    int  received_bytes;  //varialbe to record the message send info
    int message_q; //variable to record which message queue to send to
    word_t *f; //word T struct t

//set f equal to the current node
    f = *(word_t **)node;
    if(which == 1 || which == 3)
    {
//                                                                              printf("      %d %s     QUEUE NO: %d \n", f->number, f->word, f->message_q_no);
        message_q = f->message_q_no;
        message_struct.mtype = f->number;
        strcpy(message_struct.mtext, f->word);
        received_bytes =0; 
//                                                                                                  print what was put into the message_struct
//                                                                                                   printf(" %d %s \n", message_struct.mtype, message_struct.mtext);
        received_bytes = msgsnd(message_q, &message_struct, sizeof(message_struct.mtext), MSG_NOERROR);
                                                                                                  printf(" WALKER sent [%d] type (%d)  (%s) \n", message_q, message_struct.mtype, message_struct.mtext);
//                                                                                                  printf(" child [%d] : %s  \n", message_array[i], rcv.mtext);
    }
}
